package com.sxhuayuan.parking.socket;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.TaskExecutor;

import com.sxhuayuan.parking.socket.handler.ParkingLotInterfaceHandler;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;

/**
 * 车场接口转发服务。
 * 
 * 提供与中台的tcp长连接，通过中台转发来请求车场接口服务。
 * 
 * @author gy
 */
public class ParkingLotInterfaceWebSocket implements InitializingBean, DisposableBean {

	static Logger log = LoggerFactory.getLogger(ParkingLotInterfaceWebSocket.class);

	private int port;
	private ChannelFuture channelFuture;

	@Autowired
	TaskExecutor taskExecutor;
	@Autowired
	ParkingLotInterfaceHandler parkingLotInterfaceHandler;

	public ParkingLotInterfaceWebSocket() {
		super();
	}

	@Override
	public void destroy() throws Exception {
		if (channelFuture != null) {
			log.debug("netty 关闭");
			channelFuture.cancel(true);
		}
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		taskExecutor.execute(new Runnable() {
			@Override
			public void run() {
				try {
					EventLoopGroup bossGroup = new NioEventLoopGroup();
					EventLoopGroup group = new NioEventLoopGroup();
					try {
						ServerBootstrap sb = new ServerBootstrap();
						sb.option(ChannelOption.SO_BACKLOG, 1024);
						sb.group(group, bossGroup) // 绑定线程池
								.channel(NioServerSocketChannel.class) // 指定使用的channel
								.localAddress(port)// 绑定监听端口
								.childHandler(new ChannelInitializer<SocketChannel>() { // 绑定客户端连接时候触发操作

									@Override
									protected void initChannel(SocketChannel ch) throws Exception {
										log.debug("收到新连接");
										// websocket协议本身是基于http协议的，所以这边也要使用http解编码器
										ch.pipeline().addLast(new HttpServerCodec());
										// 以块的方式来写的处理器
										ch.pipeline().addLast(new ChunkedWriteHandler());
										ch.pipeline().addLast(new HttpObjectAggregator(8192));
										ch.pipeline().addLast(parkingLotInterfaceHandler);
										ch.pipeline().addLast(new WebSocketServerProtocolHandler("/api/proxy", null, true, 65536 * 10));
									}
								});
						channelFuture = sb.bind().sync(); // 服务器异步创建绑定
						log.debug("车场服务跳转启动，正在监听： " + channelFuture.channel().localAddress());
						channelFuture.channel().closeFuture().sync(); // 关闭服务器通道
					} finally {
						log.debug("正在释放资源...");
						group.shutdownGracefully().sync(); // 释放线程池资源
						bossGroup.shutdownGracefully().sync();
					}
				} catch (Exception e) {
					log.error("", e);
				}
			}
		});
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

}
